package qc.module.qms.api.job;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import qc.common.core.exception.QCPromptException;
import qc.common.core.json.JsonParserUtil;
import qc.common.core.utils.SqlRunnerUtil;
import qc.module.platform.dto.dbTable.DBTableFullDto;
import qc.module.qms.api.RestTemplatePlatform;
import qc.module.qms.dto.exchange.category.ExchangeCategoryDto;
import qc.module.qms.dto.exchange.ynslt.ExSltPptnRDto;
import qc.module.qms.dto.exchange.ynslt.ExSltRsvrRDto;
import qc.module.qms.dto.station.StationDto;
import qc.module.qms.service.QmsStationService;
import qc.module.qms.service.exchange.ExchangeCategoryService;
import tech.powerjob.worker.core.processor.ProcessResult;
import tech.powerjob.worker.core.processor.TaskContext;
import tech.powerjob.worker.core.processor.sdk.BasicProcessor;

import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * TransferToYnhjptProcessor
 *
 * @author QuCheng Tech
 * @since 2024/1/29
 */
@Component
public class TransferToYnhjptProcessor implements BasicProcessor {

    @Autowired
    private QmsStationService stationService;
    @Autowired
    private ExchangeCategoryService categoryService;

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 上传省汇集平台接口访问凭据，appid对应的token；需要根据appid和appkey调用登录接口获取
     */
    private Map<String, String> tokenMap = new HashMap<>();

    //静态定义--云南省汇集平台上传数据分类ID集合
    public final int[] ynhjptCategoryIds = new int[]{0x1, 0x2};

    /**
     * 上传省汇集平台接口URL
     */
    public final String SltYnhjptApiUrl = "http://112.112.128.35:2355";

    @Autowired
    private RestTemplatePlatform restTemplatePlatform;

    @Override
    public ProcessResult process(TaskContext taskContext) throws SQLException, QCPromptException {
        System.out.println("====================开始获取上传数据=========================");
        //遍历交换数据分类id集合
        if (ynhjptCategoryIds != null && ynhjptCategoryIds.length > 0x0) {
            for (int categoryId : ynhjptCategoryIds) {
                //获取分类中的站点集合
                List<StationDto> categoryStations = stationService.getByCategoryId(categoryId);
                if (categoryStations != null && categoryStations.size() > 0x0) {
                    //数据分类中有交换站点，判断是否需要处理
                    //获取交换数据分类信息，需要使用其中设置的交换频率等参数
                    ExchangeCategoryDto category = categoryService.get(categoryId);
                    if (category != null && StringUtils.isNotBlank(category.getTablecode())) {
                        //根据数据库表编码获取完整信息，再从信息中获取sql语句、查询数据库连接信息和列信息
                        DBTableFullDto tableFullInfo = restTemplatePlatform.getDbTableFullInfo(category.getTablecode());
                        //数据库连接信息
                        String dbUrl = "";
                        String dbUser = "";
                        String dbPassword = "";
                        if (tableFullInfo != null) {
                            if (tableFullInfo.getDb() != null) {
                                //解析数据库连接信息
                                String dbConJsonString = tableFullInfo.getDb().getCon();
                                if (StringUtils.isNotBlank(dbConJsonString)) {
                                    //Json对象进行获取
                                    dbUrl = JsonParserUtil.getString(dbConJsonString, "url");
                                    dbUser = JsonParserUtil.getString(dbConJsonString, "user");
                                    dbPassword = JsonParserUtil.getString(dbConJsonString, "password");
                                }
                            }
                        }

                        //固定查询flag=0的标记为未上传的数据，按数据的时标升序排序
                        String sql = "SELECT * FROM " + category.getTablecode() + " WHERE flag=0 AND tm<=? ORDER BY tm ASC";
                        List<Map<String, Object>> queryData = SqlRunnerUtil.executeSelectListSql(dbUrl, dbUser, dbPassword, sql, new Date());
                        System.out.println("====================开始处理数据上传=========================");
                        if (categoryId == 0x1) {
                            //水库水位
                            //2.1 如果有未上传的水库水位数据，处理并上传
                            handleRsvrDataAndTransferToYnhjpt(queryData, dbUrl, dbUser, dbPassword, category.getTablecode());
                        } else {
                            //降雨量
                            //2.2 如果有未上传的降雨量数据，处理并上传
                            handlePptnDataAndTransferToYnhjpt(queryData, dbUrl, dbUser, dbPassword, category.getTablecode());
                        }
                    }
                }
            }
        }
        
        return new ProcessResult(true,"上传省汇集平台数据成功");
    }

    /**
     * 处理水库水位待上传数据，然后逐条上传到云南汇集平台
     * @param exSltRsvrRData
     */
    private void handleRsvrDataAndTransferToYnhjpt(List<Map<String, Object>> exSltRsvrRData,
                                                   String dbUrl,String dbUser,String dbPassword,String tableCode) throws SQLException {
        if (CollectionUtils.isNotEmpty(exSltRsvrRData)) {
            //循环处理水库水位数据
            for (Map<String, Object> dataMap : exSltRsvrRData) {
                //初始化上传数据信息验证结果，默认为验证为有效
                boolean isExchangeDataValid = true;
                StringBuilder sb = new StringBuilder();

                //数据上传接口中需要的appid和appkey
                String appid = null;
                String appkey = null;
                //处理为要上传的数据格式
                ExSltRsvrRDto exSltRsvrRDto = new ExSltRsvrRDto();
                for (String key : dataMap.keySet()) {
                    System.out.println("rsvr:key = " + key + ", value = " + dataMap.get(key));
                    if (key.equals("appid"))
                        if (dataMap.get(key) != null && dataMap.get(key) != "") appid = dataMap.get(key).toString();
                    if (key.equals("appkey"))
                        if (dataMap.get(key) != null && dataMap.get(key) != "") appkey = dataMap.get(key).toString();
                    if (key.equals("rscd")) exSltRsvrRDto.setRscd(dataMap.get(key).toString());
                    if (key.equals("stcd")) exSltRsvrRDto.setStcd(dataMap.get(key).toString());
                    if (key.equals("tm")) exSltRsvrRDto.setTm(dataMap.get(key).toString());
                    if (key.equals("z")) exSltRsvrRDto.setZ(new BigDecimal(dataMap.get(key).toString()));
                    if (key.equals("w")) exSltRsvrRDto.setW(new BigDecimal(dataMap.get(key).toString()));
                    if (key.equals("zrcd")) if (dataMap.get(key) != null && dataMap.get(key) != "")
                        exSltRsvrRDto.setZrcd(dataMap.get(key).toString());
                    else exSltRsvrRDto.setZrcd("");
                }

                //没有上传登录参数appid不处理
                if (StringUtils.isBlank(appid)) {
                    isExchangeDataValid = false;
                    sb.append("appid为空");
                }
                //没有上传登录参数appkey不处理
                if (isExchangeDataValid == true) {
                    if (StringUtils.isBlank(appkey)) {
                        isExchangeDataValid = false;
                        sb.append("appkey为空");
                    }
                }
                //调用上传接口所需的token
                String token = null;
                //根据id，key请求token
                if (isExchangeDataValid == true) {
                    //如果在已记录的tokenMap中有appid对应的appkey则直接使用，如果没有调用一次接口获取appid对应的appkey并进行记录
                    token = tokenMap.get(appid);
                    if (StringUtils.isBlank(token)) {
                        //如果在记录的appid和token对应集合中没有，调用接口进行登录获取
                        getAccessToken(appid, appkey);
                        //调用登录接口后，再进行获取
                        token = tokenMap.get(appid);
                    }
                }
                //token不为空时才进行数据上传，如果token为空本次不进行数据上传处理
                if (StringUtils.isNotBlank(token)) {
                    if (isExchangeDataValid == true) {
                        //上传水库水位url
                        String rsvrUrl = SltYnhjptApiUrl + "/api/OBZ";
                        //请求头
                        HttpHeaders headers = new HttpHeaders();
                        headers.setContentType(MediaType.APPLICATION_JSON);
                        headers.add("Authorization", token);

                        //请求体
                        HttpEntity<ExSltRsvrRDto> httpEntity = new HttpEntity<>(exSltRsvrRDto, headers);
                        //响应类型
                        ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<String>() {
                        };
                        //调用上报数据接口上报数据
                        //设置超时时间
                        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
                        httpRequestFactory.setConnectionRequestTimeout(50 * 1000);
                        httpRequestFactory.setConnectTimeout(50 * 1000);
                        httpRequestFactory.setReadTimeout(50 * 1000);
                        restTemplate.setRequestFactory(httpRequestFactory);
                        ResponseEntity<String> responseEntity = null;
                        try {
                            responseEntity = restTemplate.exchange(rsvrUrl, HttpMethod.POST, httpEntity, responseType);
                            //解析请求结果
                            if (responseEntity != null) {
                                String result = responseEntity.getBody();
                                System.out.println("上传水位数据result：" + result);
                                JSONObject responseJsonObject = JSONObject.parseObject(result);
                                if (responseJsonObject != null) {
                                    String status = responseJsonObject.getString("status");
                                    if (status.equals("401")) {
                                        //如果状态码为401，token无效，重新获取
                                        //状态码为401时，不对数据的上传结果进行修改，以便于下次再进行上传
                                        getAccessToken(appid, appkey);
                                    } else if (status.equals("200")) {
                                        //如果状态码为200，上传数据成功，修改数据记录：状态为已上传，设置上传时间
                                        System.out.println("=================修改数据库水库水位数据记录状态================================");
                                        String sql = "UPDATE " + tableCode + " SET flag = 1,sendtm = ? WHERE rscd = ? AND stcd = ? AND tm = ?";
                                        SqlRunnerUtil.executeUpdateSql(dbUrl, dbUser, dbPassword, sql, new Date(), exSltRsvrRDto.getRscd(), exSltRsvrRDto.getStcd(), exSltRsvrRDto.getTm());
                                    } else {
                                        //如果状态码为其他，标记为数据上传失败
                                        System.out.println("=================修改数据库水库水位数据记录状态================================");
                                        String sql = "UPDATE " + tableCode + " SET flag = 2,msg= ? , sendtm = ? WHERE rscd = ? AND stcd = ? AND tm = ?";
                                        SqlRunnerUtil.executeUpdateSql(dbUrl, dbUser, dbPassword, sql, responseJsonObject.getString("msg"), new Date(), exSltRsvrRDto.getRscd(), exSltRsvrRDto.getStcd(), exSltRsvrRDto.getTm());
                                    }
                                }
                            }
                        } catch (HttpClientErrorException e) {
                            String resBody = e.getResponseBodyAsString();
                            System.out.println("访问上传水库水位接口异常：" + resBody);
                            JSONObject resBodyJsonObject = JSONObject.parseObject(resBody);
                            if (resBodyJsonObject == null) {
                                getAccessToken(appid, appkey);
                                System.out.println("异常后重新请求token的id：" + appkey + ", key: " + appkey);
                            }

                            //调用上传结果异常时，修改上传标记为失败和上传处理结果信息
                            sb.append(resBody);
                            System.out.println("=================修改数据库水库水位数据记录状态================================");
                            String sql = "UPDATE " + tableCode + " SET flag = 2,msg= ? ,sendtm = ? WHERE rscd = ? AND stcd = ? AND tm = ?";
                            SqlRunnerUtil.executeUpdateSql(dbUrl, dbUser, dbPassword, sql, sb.toString(), new Date(), exSltRsvrRDto.getRscd(), exSltRsvrRDto.getStcd(), exSltRsvrRDto.getTm());
                        }
                    } else {
                        //上传数据中的信息验证未通过，修改上传标记和上传处理结果
                        String sql = "UPDATE " + tableCode + " SET flag = 3,msg= ? ,sendtm = ? WHERE rscd = ? AND stcd = ? AND tm = ?";
                        SqlRunnerUtil.executeUpdateSql(dbUrl, dbUser, dbPassword, sql, sb.toString(), new Date(), exSltRsvrRDto.getRscd(), exSltRsvrRDto.getStcd(), exSltRsvrRDto.getTm());
                    }
                }
            }
        }
    }

    /**
     * 处理降雨量待上传数据，然后逐条上传到云南汇集平台
     * @param exSltPptnRData
     */
    private void handlePptnDataAndTransferToYnhjpt(List<Map<String, Object>> exSltPptnRData,
                                                   String dbUrl,String dbUser,String dbPassword,String tableCode) throws SQLException {
        if (CollectionUtils.isNotEmpty(exSltPptnRData)) {
            //循环处理降雨量数据
            for (Map<String, Object> dataMap : exSltPptnRData) {//初始化上传数据信息验证结果，默认为验证为有效
                boolean isExchangeDataValid = true;
                StringBuilder sb = new StringBuilder();

                //数据上传接口中需要的appid和appkey
                String appid = null;
                String appkey = null;
                //处理为要上传的数据格式
                ExSltPptnRDto exSltPptnRDto = new ExSltPptnRDto();
                for (String key : dataMap.keySet()) {
                    System.out.println("pptn:key = " + key + ", value = " + dataMap.get(key));
                    if (key.equals("appid"))
                        if (dataMap.get(key) != null && dataMap.get(key) != "") appid = dataMap.get(key).toString();
                    if (key.equals("appkey"))
                        if (dataMap.get(key) != null && dataMap.get(key) != "") appkey = dataMap.get(key).toString();
                    if (key.equals("stcd")) exSltPptnRDto.setStcd(dataMap.get(key).toString());
                    if (key.equals("tm")) exSltPptnRDto.setTm(dataMap.get(key).toString());
                    if (key.equals("dr")) exSltPptnRDto.setDr(dataMap.get(key).toString());
                    if (key.equals("p")) exSltPptnRDto.setP(new BigDecimal(dataMap.get(key).toString()));
                    if (key.equals("prcd")) if (dataMap.get(key) != null && dataMap.get(key) != "")
                        exSltPptnRDto.setPrcd(dataMap.get(key).toString());
                    else exSltPptnRDto.setPrcd("");
                }

                //没有上传登录参数appid不处理
                if (StringUtils.isBlank(appid)) {
                    isExchangeDataValid = false;
                    sb.append("appid为空");
                }
                //没有上传登录参数appkey不处理
                if (isExchangeDataValid == true) {
                    if (StringUtils.isBlank(appkey)) {
                        isExchangeDataValid = false;
                        sb.append("appkey为空");
                    }
                }
                //调用上传接口所需的token
                String token = null;
                //根据id，key请求token
                if (isExchangeDataValid == true) {
                    //如果在已记录的tokenMap中有appid对应的appkey则直接使用，如果没有调用一次接口获取appid对应的appkey并进行记录
                    token = tokenMap.get(appid);
                    if (StringUtils.isBlank(token)) {
                        //如果在记录的appid和token对应集合中没有，调用接口进行登录获取
                        getAccessToken(appid, appkey);
                        //调用登录接口后，再进行获取
                        token = tokenMap.get(appid);
                    }
                }
                //token不为空时才能调用接口进行上传，如果为空等待下次获取
                if (StringUtils.isNotBlank(token)) {
                    if (isExchangeDataValid == true) {
                        //上传降雨量url
                        String pptnUrl = SltYnhjptApiUrl + "/api/OBP";
                        //请求头
                        HttpHeaders headers = new HttpHeaders();
                        headers.setContentType(MediaType.APPLICATION_JSON);
                        headers.add("Authorization", token);

                        //请求体
                        HttpEntity<ExSltPptnRDto> httpEntity = new HttpEntity<>(exSltPptnRDto, headers);
                        //响应类型
                        ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<String>() {
                        };
                        //调用上报数据接口上报数据
                        //设置超时时间
                        HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
                        httpRequestFactory.setConnectionRequestTimeout(50 * 1000);
                        httpRequestFactory.setConnectTimeout(50 * 1000);
                        httpRequestFactory.setReadTimeout(50 * 1000);
                        restTemplate.setRequestFactory(httpRequestFactory);
                        ResponseEntity<String> responseEntity = null;
                        try {
                            responseEntity = restTemplate.exchange(pptnUrl, HttpMethod.POST, httpEntity, responseType);
                            //解析请求结果
                            if (responseEntity != null) {
                                String result = responseEntity.getBody();
                                System.out.println("上传降雨量数据result：" + result);
                                JSONObject responseJsonObject = JSONObject.parseObject(result);
                                if (responseJsonObject != null) {
                                    String status = responseJsonObject.getString("status");
                                    if (status.equals("401")) {
                                        //如果状态码为401，token无效，重新获取
                                        //状态码为401时，不对数据的上传结果进行修改，以便于下次再进行上传
                                        getAccessToken(appid, appkey);
                                    } else if (status.equals("200")) {
                                        //如果状态码为200，上传数据成功，修改数据记录：状态为已上传，设置上传时间
                                        System.out.println("=================修改数据库降雨量数据记录状态================================");
                                        String sql = "UPDATE " + tableCode + " SET flag = 1,sendtm = ? WHERE stcd = ? AND tm = ?";
                                        SqlRunnerUtil.executeUpdateSql(dbUrl, dbUser, dbPassword, sql, new Date(), exSltPptnRDto.getStcd(), exSltPptnRDto.getTm());
                                    } else {
                                        //如果状态码为其他，标记数据为上传失败
                                        System.out.println("=================修改数据库降雨量数据记录状态================================");
                                        String sql = "UPDATE " + tableCode + " SET flag = 2,msg= ? ,sendtm = ? WHERE stcd = ? AND tm = ?";
                                        SqlRunnerUtil.executeUpdateSql(dbUrl, dbUser, dbPassword, sql, responseJsonObject.getString("msg"), new Date(), exSltPptnRDto.getStcd(), exSltPptnRDto.getTm());
                                    }
                                }
                            }
                        } catch (HttpClientErrorException e) {
                            String resBody = e.getResponseBodyAsString();
                            System.out.println("访问上传将降雨量接口异常：" + resBody);
                            JSONObject resBodyJsonObject = JSONObject.parseObject(resBody);
                            if (resBodyJsonObject == null) {
                                getAccessToken(appid, appkey);
                                System.out.println("异常后重新请求token的id：" + appkey + ", key: " + appkey);
                            }

                            //调用上传结果异常时，修改上传标记为失败和上传处理结果信息
                            sb.append(resBody);
                            System.out.println("=================修改数据库降雨量数据记录状态================================");
                            String sql = "UPDATE " + tableCode + " SET flag = 2,msg= ? ,sendtm = ? WHERE stcd = ? AND tm = ?";
                            SqlRunnerUtil.executeUpdateSql(dbUrl, dbUser, dbPassword, sql, sb.toString(), new Date(), exSltPptnRDto.getStcd(), exSltPptnRDto.getTm());
                        }
                    } else {
                        //上传数据中的信息验证未通过，修改上传标记和上传处理结果
                        String sql = "UPDATE " + tableCode + " SET flag = 3,msg= ? ,sendtm = ? WHERE stcd = ? AND tm = ?";
                        SqlRunnerUtil.executeUpdateSql(dbUrl, dbUser, dbPassword, sql, sb.toString(), new Date(), exSltPptnRDto.getStcd(), exSltPptnRDto.getTm());
                    }
                }
            }
        }
    }

    /**
     * 获取登录access_token
     * @param id 登录请求参数id
     * @param key 登录请求参数key
     */
    private void getAccessToken(String id,String key){
        String token = "";
        String url = SltYnhjptApiUrl + "/api/login";
        
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        
        //请求参数
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id",id);
        jsonObject.put("key",key);

        //请求体
        HttpEntity<JSONObject> httpEntity = new HttpEntity<>(jsonObject,headers);
        //响应类型
        ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<String>() {
        };
        //调用上报数据接口上报数据
        ResponseEntity<String> responseEntity = restTemplate.exchange(url, HttpMethod.POST,httpEntity,responseType);

        System.out.println(responseEntity);
        //解析请求结果
        String result = responseEntity.getBody();
        JSONObject responseJsonObject = JSONObject.parseObject(result);
        if (responseJsonObject != null){
            String status = responseJsonObject.getString("status");
            if (status.equals("200")){
                token = responseJsonObject.getString("access_token");
            }

        }
        tokenMap.put(id,"Bearer " + token);
    }
}
